<?php

abstract
class HTTPMessage
{
    protected $first;
    protected $headers;
    protected $body;
    protected $headersNames;

    function __construct($msg)
    {
        if (strlen($msg) === 0) {
            throw new Exception('HTTP message is empty');
        }

        /**
         * 1. Разбиваем сообщение на строки
         * 2. $this->first.      Отделяем первую строку — статус/метод
         * 3. $this->body.       Отделяем тело сообщения
         * 4. $headersRAW. Создаём массив заголовков
         */
        $lines = explode("\r\n", $msg);
        $this->first = array_shift($lines);
        $headersRAW = array();
        $linesNumber = count($lines);
        for ($i = 0; $i < $linesNumber; $i++) {
            $line = array_shift($lines);
            if (strlen($line) == 0) {
                break;
            }
            if (preg_match('/\\s/s', $line[0])) {
                if (count($headersRAW)) {
                    $headersRAW[count($headersRAW)-1] .= ' '.trim($line);
                }
            } else {
                $headersRAW[] = $line;
            }
        }
        print_r("\n\nRESPONSE\n\n");
        print_r($headersRAW);
        $this->body = implode("\r\n", $lines);

        /**
         * Преобразуем массив заголовков $headersRAW в массив ассоциативных массивов вида:
         * array(
         *      'name' => <имя заголовка в нижнем регистре>,
         *      'value' => <значение заголовка>
         * )
         */
        $headers = array();
        foreach ($headersRAW as $line) {
            $comaPos = strpos($line, ':');
            if ($comaPos > 0) {
                $name = strtolower(trim(substr($line, 0, $comaPos)));
                @$this->headersNames[$name]++;
                $value = trim(substr($line, $comaPos+1));
                if (strlen($name)) {
                    $headers[] = array(
                        'name' => $name,
                        'value' => $value
                    );
                }
            }
        }

        $this->headers = $headers;
    }

    function getBody()
    {
        return $this->body;
    }

    function getHeaderValues($name)
    {
        $name = strtolower($name);
        $values = array();
        foreach ($this->headers as $header) {
            if ($name == $header['name']) {
                $values[] = $header['value'];
            }
        }

        return $values;
    }

    function getHeadersNames()
    {
        return array_keys($this->headersNames);
    }
}

class HTTPRequest extends HTTPMessage
{
}

class HTTPResponse extends HTTPMessage
{
    protected $code;

    function __construct($msg)
    {
        parent::__construct($msg);

        if (preg_match('/^[^\\s]+\\s+(\\d{3})\\b/', $this->first, $matches) && isset($matches[1])) {
            $this->code = intval($matches[1]);
        } else {
            throw new Exception('Invalid HTTP-response: unparsed hed-line');
        }
    }

    function getStatusCode()
    {
        return $this->code;
    }
}

?>